﻿using System;
using System.Linq;
using System.IO;
using Utilities.IO.ExtensionMethods.Enums;
using Utilities.DataTypes.ExtensionMethods;


namespace Utilities.IO.ExtensionMethods
{
    /// <summary>
    /// 扩展方法 <see cref="System.IO.DirectoryInfo"/>
    /// </summary>
    public static class DirectoryInfoExtensions
    {
        #region 扩展方法

        #region 复制到

        /// <summary>
        /// 目录复制到另一个位置
        /// </summary>
        /// <param name="Source">源目录 </param>
        /// <param name="Destination">目的目录</param>
        /// <param name="Recursive">应该递归复制(是否复制文件夹下目录，为false则不复制文件夹内容只复制本路径下文件)</param>
        /// <param name="Options">在复制中使用的选项</param>
        /// <returns>目标信息的DirectoryInfo</returns>
        public static DirectoryInfo CopyTo(this DirectoryInfo Source, string Destination, bool Recursive = true, CopyOptions Options = CopyOptions.CopyAlways)
        {
            if (Source == null)
                throw new ArgumentNullException("Source");
            if (!Source.Exists)
                throw new DirectoryNotFoundException("Source directory " + Source.FullName + " not found.");
            if (string.IsNullOrEmpty(Destination))
                throw new ArgumentNullException("Destination");
            DirectoryInfo DestinationInfo = new DirectoryInfo(Destination);
            DestinationInfo.Create();
            foreach (FileInfo TempFile in Source.EnumerateFiles())
            {
                if (Options == CopyOptions.CopyAlways)
                {
                    TempFile.CopyTo(Path.Combine(DestinationInfo.FullName, TempFile.Name), true);
                }
                else if (Options == CopyOptions.CopyIfNewer)
                {
                    if (File.Exists(Path.Combine(DestinationInfo.FullName, TempFile.Name)))
                    {
                        FileInfo FileInfo = new FileInfo(Path.Combine(DestinationInfo.FullName, TempFile.Name));
                        if (FileInfo.LastWriteTime.CompareTo(TempFile.LastWriteTime) < 0)
                            TempFile.CopyTo(Path.Combine(DestinationInfo.FullName, TempFile.Name), true);
                    }
                    else
                    {
                        TempFile.CopyTo(Path.Combine(DestinationInfo.FullName, TempFile.Name), true);
                    }
                }
                else if (Options == CopyOptions.DoNotOverwrite)
                {
                    TempFile.CopyTo(Path.Combine(DestinationInfo.FullName, TempFile.Name), false);
                }
            }
            if (Recursive)
            {
                foreach (DirectoryInfo SubDirectory in Source.EnumerateDirectories())
                    SubDirectory.CopyTo(Path.Combine(DestinationInfo.FullName, SubDirectory.Name), Recursive, Options);
            }
            return new DirectoryInfo(Destination);
        }

        #endregion

        #region 删除全部

        /// <summary>
        /// Deletes directory and all content found within it
        /// </summary>
        /// <param name="Info">Directory info object</param>
        public static void DeleteAll(this DirectoryInfo Info)
        {
            if (!Info.Exists)
                return;
            Info.DeleteFiles();
            Info.EnumerateDirectories().ForEach(x => x.DeleteAll());
            Info.Delete(false);
        }

        #endregion

        #region 删除新目录

        /// <summary>
        /// 删除晚于指定日期的目录
        /// </summary>
        /// <param name="Directory">目录内容</param>
        /// <param name="CompareDate">要比较的日期</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>返回目录对象</returns>
        public static DirectoryInfo DeleteDirectoriesNewerThan(this DirectoryInfo Directory, DateTime CompareDate, bool Recursive = false)
        {
            if (!Directory.Exists)
                throw new DirectoryNotFoundException("Directory");
            if (CompareDate == null)
                throw new ArgumentNullException("CompareDate");
            Directory.EnumerateDirectories("*", Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                     .Where(x => x.LastWriteTime > CompareDate)
                     .ForEach(x => x.DeleteAll());
            return Directory;
        }

        #endregion

        #region 删除旧目录

        /// <summary>
        /// 删除早于指定日期的目录
        /// </summary>
        /// <param name="Directory">目录内容</param>
        /// <param name="CompareDate">要比较的日期</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>返回目录对象</returns>
        public static DirectoryInfo DeleteDirectoriesOlderThan(this DirectoryInfo Directory, DateTime CompareDate, bool Recursive = false)
        {
            if (!Directory.Exists)
                throw new DirectoryNotFoundException("Directory");
            if (CompareDate == null)
                throw new ArgumentNullException("CompareDate");
            Directory.EnumerateDirectories("*", Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                     .Where(x => x.LastWriteTime < CompareDate)
                     .ForEach(x => x.DeleteAll());
            return Directory;
        }

        #endregion

        #region 删除文件

        /// <summary>
        /// 从目录中删除文件
        /// </summary>
        /// <param name="Directory">要删除的目录中的文件</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>返回目录对象</returns>
        public static DirectoryInfo DeleteFiles(this DirectoryInfo Directory, bool Recursive = false)
        {
            if (!Directory.Exists)
                throw new DirectoryNotFoundException("Directory");
            Directory.EnumerateFiles("*", Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                     .ForEach(x => x.Delete());
            return Directory;
        }

        #endregion

        #region 删除新文件

        /// <summary>
        /// 删除晚于指定日期的文件
        /// </summary>
        /// <param name="Directory">目录内容</param>
        /// <param name="CompareDate">要比较的日期</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>返回目录对象</returns>
        public static DirectoryInfo DeleteFilesNewerThan(this DirectoryInfo Directory, DateTime CompareDate, bool Recursive = false)
        {
            if (!Directory.Exists)
                throw new DirectoryNotFoundException("Directory");
            if (CompareDate == null)
                throw new ArgumentNullException("CompareDate");
            Directory.EnumerateFiles("*", Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                     .Where(x => x.LastWriteTime > CompareDate)
                     .ForEach(x => x.Delete());
            return Directory;
        }

        #endregion

        #region 删除旧文件

        /// <summary>
        /// 删除早于指定日期的文件
        /// </summary>
        /// <param name="Directory">目录内容</param>
        /// <param name="CompareDate">要比较的日期</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>返回目录对象</returns>
        public static DirectoryInfo DeleteFilesOlderThan(this DirectoryInfo Directory, DateTime CompareDate, bool Recursive = false)
        {
            if (!Directory.Exists)
                throw new DirectoryNotFoundException("Directory");
            if (CompareDate == null)
                throw new ArgumentNullException("CompareDate");
            Directory.EnumerateFiles("*", Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                     .Where(x => x.LastWriteTime < CompareDate)
                     .ForEach(x => x.Delete());
            return Directory;
        }

        #endregion

        #region 驱动器信息

        /// <summary>
        /// 获取目录的驱动器信息
        /// </summary>
        /// <param name="Directory">要获取驱动器信息的目录</param>
        /// <returns>连接到目录的驱动器信息</returns>
        public static DriveInfo DriveInfo(this DirectoryInfo Directory)
        {
            if (Directory == null)
                throw new ArgumentNullException("Directory");
            return new DriveInfo(Directory.Root.FullName);
        }

        #endregion

        #region 大小

        /// <summary>
        /// 获取目录内的所有文件的大小
        /// </summary>
        /// <param name="Directory">目录</param>
        /// <param name="SearchPattern">搜索模式用于告诉要包括哪些文件 (默认为所有)</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>目录大小</returns>
        public static long Size(this DirectoryInfo Directory, string SearchPattern = "*", bool Recursive = false)
        {
            if (Directory == null)
                throw new ArgumentNullException("Directory");
            return Directory.EnumerateFiles(SearchPattern, Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                            .Sum(x => x.Length);
        }

        #endregion

        #region 设置属性

        /// <summary>
        /// 设置目录的属性
        /// </summary>
        /// <param name="Directory">目录</param>
        /// <param name="Attributes">要设置的属性</param>
        /// <param name="Recursive">是否递归（当前目录，还是子目录）</param>
        /// <returns>目录对象</returns>
        public static DirectoryInfo SetAttributes(this DirectoryInfo Directory, System.IO.FileAttributes Attributes, bool Recursive = false)
        {
            Directory.EnumerateFiles()
                     .ForEach(x => x.SetAttributes(Attributes));
            if (Recursive)
                Directory.EnumerateDirectories().ForEach(x => x.SetAttributes(Attributes, true));
            return Directory;
        }

        #endregion

        #endregion
    }
}
